package com.aiju.common.thread;

import com.aiju.support.deque.LIFOLinkedBlockingDeque;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @auther: 佐为
 * @date: 2016.8.15
 * @Description: 线程池提供类
 */

public class AsyncExecutor {

    /**
     * 自定义线程池
     *
     * @param threadPoolSize      并发量
     * @param threadPriority      线程等级
     * @param tasksProcessingType 工作方式 1、先进先出 2、后进先出
     * @return
     */
    public static Executor createExecutor(int threadPoolSize, int threadPriority,
                                          QueueType tasksProcessingType) {
        boolean lifo = tasksProcessingType == QueueType.LIFO;
        BlockingQueue<Runnable> taskQueue =
                lifo ? new LIFOLinkedBlockingDeque<Runnable>() : new LinkedBlockingQueue<Runnable>();
        return new ThreadPoolExecutor(threadPoolSize, threadPoolSize, 0L, TimeUnit.MILLISECONDS, taskQueue,
                createThreadFactory(threadPriority, "uil-pool-"));
    }

    /**
     * 创建一个可缓存线程池，如果线程池长度超过处理需要，可灵活回收空闲线程，若无可回收，则新建线程。
     */
    public static Executor createTaskDistributor() {
        return Executors.newCachedThreadPool(createThreadFactory(Thread.NORM_PRIORITY, "uil-pool-d-"));
    }

    /**
     * 创建一个定时操作的线程池，替代timer
     */
    public static ScheduledExecutorService createScheduledExecutor() {
        return Executors.newSingleThreadScheduledExecutor(createThreadFactory(Thread.NORM_PRIORITY, "uil-pool-s-"));
    }

    /**
     * 创建线程工厂
     *
     * @param threadPriority   线程等级
     * @param threadNamePrefix 线程池名
     * @return
     */
    private static ThreadFactory createThreadFactory(int threadPriority, String threadNamePrefix) {
        return new DefaultThreadFactory(threadPriority, threadNamePrefix);
    }

    private static class DefaultThreadFactory implements ThreadFactory {

        private static final AtomicInteger poolNumber = new AtomicInteger(1);

        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;
        private final int threadPriority;

        DefaultThreadFactory(int threadPriority, String threadNamePrefix) {
            this.threadPriority = threadPriority;
            group = Thread.currentThread().getThreadGroup();
            namePrefix = threadNamePrefix + poolNumber.getAndIncrement() + "-thread-";
        }

        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
            if (t.isDaemon()) t.setDaemon(false);
            t.setPriority(threadPriority);
            return t;
        }
    }

}
